﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Net;

namespace HexTileBoard
{
    public class Player
    {
        /// <summary>
        /// Player index for local players
        /// </summary>
        public PlayerIndex playerIndex;

        /// <summary>
        /// Player's side for the game
        /// </summary>
        public Color color;
        private PlayerColor side;
        public PlayerColor Side
        {
            get { return side; }
        }

        /// <summary>
        /// Indicator for whether the player is an AI player or not.
        /// </summary>
        public bool IsAI;

        /// <summary>
        /// Reference to game board for player access.
        /// </summary>
        public Board PlayerBoard;

        /// <summary>
        /// The camera for displaying what the player is looking at.
        /// </summary>
        public SimpleCamera Camera;

        public TileSimple SelectedTile;

        /// <summary>
        /// Allows the player to build without being adjacent to influence
        /// </summary>
        public bool canBuildFirst = true;

        // resources
        public Dictionary<HexTileResource, int> CurrentResources = new Dictionary<HexTileResource, int>();
        public Dictionary<HexTileResource, int> OwnedResources = new Dictionary<HexTileResource, int>();
        public List<int> tilesOwned = new List<int>();

        /// <summary>
        /// Constructor for player components.
        /// </summary>
        /// <param name="_board"></param>
        /// <param name="_side"></param>
        public Player(Board _board, PlayerColor _side, bool _IsAI, PlayerIndex _playerIndex, Vector3 _cameraPosition, Vector3 _cameraTarget, Viewport _viewport)
        {
            // Set player index for local players
            this.playerIndex = _playerIndex;

            // Initialize the camera
            this.Camera = new SimpleCamera();
            this.Camera.Create(_cameraPosition, _cameraTarget, _viewport, SimpleCamera.ViewportLocation.FullScreen);
            //this.Camera.Reset(_cameraPosition, _cameraTarget);

            // Set board play variables
            this.PlayerBoard = _board;
            this.side = _side;
            this.IsAI = _IsAI;

            // Set color for drawing
            switch (_side)
            {
                case PlayerColor.Blue:
                    this.color = Color.Blue; break;
                case PlayerColor.Green:
                    this.color = Color.Green; break;
                case PlayerColor.None:
                    this.color = Color.Transparent; break;
                case PlayerColor.Red:
                    this.color = Color.Red; break;
                case PlayerColor.Yellow:
                    this.color = Color.Yellow; break;
            }

            this.OwnedResources[HexTileResource.None] = 0;
            this.OwnedResources[HexTileResource.Clay] = 0;
            this.OwnedResources[HexTileResource.Iron] = 0;
            this.OwnedResources[HexTileResource.Stone] = 0;
            this.OwnedResources[HexTileResource.Wheat] = 0;
            this.OwnedResources[HexTileResource.Wood] = 0;

            this.CurrentResources[HexTileResource.Clay] = 50;
            this.CurrentResources[HexTileResource.Iron] = 5;
            this.CurrentResources[HexTileResource.Stone] = 50;
            this.CurrentResources[HexTileResource.Wheat] = 10;
            this.CurrentResources[HexTileResource.Wood] = 50;
        }

        public void Draw(GameTime _gameTime)
        {
            if (IsAI)
            {
            }
            else
            {
            }

            //throw new NotImplementedException();
        }

        public void Update(GameTime _gameTime)
        {
            if (IsAI && PlayerBoard != null && !PlayerBoard.AIThinking && this == PlayerBoard.currentPlayer && !PlayerBoard.gameOver)
            {
                PlayerBoard.AIThinking = true;
#if XBOX
                Thread.CurrentThread.SetProcessorAffinity(5);
#endif
                System.Threading.ThreadPool.QueueUserWorkItem(Func =>
                {
                    //T result = ReadObject<T>(filename);
                    //callback(result);
                    GetBestMove(PlayerBoard);
                });
            }
            else
            {
            }

            this.Camera.Update(_gameTime);
        }

        public void HandleInput(InputState _inputState, GameTime _gameTime)
        {
            if (IsAI)
            {
            }
            else
            {
            }
        }

        public bool UpdateTower(int _selectedIndex, PlayerColor _side)
        {
            // Single threaded
            //BoardFunctions.UpgradeTower(ref PlayerBoard, _selectedIndex, _side);

            bool success = BoardFunctions.UpgradeTower(ref PlayerBoard, _selectedIndex, _side, PlayerBoard.networkSession);
            // Multithreaded
#if XBOX
                Thread.CurrentThread.SetProcessorAffinity(5);
#endif
            System.Threading.ThreadPool.QueueUserWorkItem(Func =>
            {
                //T result = ReadObject<T>(filename);
                //callback(result);
                //BoardFunctions.UpgradeTower(ref PlayerBoard, _selectedIndex, _side);
                UpdateInfluenceThreaded(PlayerBoard);
            });

            return success;
        }

        public void ReduceTower(int _sourceIndex, int _targetIndex)
        {
            // Single threaded
            //BoardFunctions.ReduceTower(ref PlayerBoard, _index);

            BoardFunctions.ReduceTower(ref PlayerBoard, _sourceIndex, _targetIndex, PlayerBoard.networkSession);
            // Multithreaded
#if XBOX
                Thread.CurrentThread.SetProcessorAffinity(5);
#endif
            System.Threading.ThreadPool.QueueUserWorkItem(Func =>
            {
                //T result = ReadObject<T>(filename);
                //callback(result);
                //BoardFunctions.UpgradeTower(ref PlayerBoard, _selectedIndex, _side);
                //ReduceTowerThreaded(PlayerBoard, _index);
                UpdateInfluenceThreaded(PlayerBoard);
            });
        }

        public void EndTurn()
        {
            // Single threaded
            //BoardFunctions.EndTurn(ref PlayerBoard);

            // Multithreaded
#if XBOX
                Thread.CurrentThread.SetProcessorAffinity(5);
#endif
            System.Threading.ThreadPool.QueueUserWorkItem(Func =>
            {
                //T result = ReadObject<T>(filename);
                //callback(result);
                //BoardFunctions.UpgradeTower(ref PlayerBoard, _selectedIndex, _side);
                EndTurnThreaded(this.PlayerBoard);
            });
        }

        public delegate void AsyncDelegate(Board _currentBoard);
        static private void GetBestMove(Board _currentBoard)
        {
            System.Threading.Thread.Sleep(BoardVariables.AIStartWaitTime);
            DateTime startTime = DateTime.Now;
            DateTime endTime;
            TimeSpan ts;

            // Analysis: 
            //      Y: balance resources with costs needed, don't consume all one resource
            //      Y: Do this by tracking # of possessed resources and weighting for what we need most
            //      Y: Also, a spot with wood is worth less than wood + clay, less than wood + clay + stone, etc
            //      Y: iron worth the least
            //      Y: Reduce score if neighboring tile is friendly tower
            //      Y: Build a bridge if immediate neighbor is friendly owned, value >= 2, and neighboring water is not already a bridge
            //      Y: when checking building, if near water, check over water too (bridge)

            //--------------------------------------------------------------
            // Trading
            //--------------------------------------------------------------
            // Cannot trade on the first turn
            if (!_currentBoard.currentPlayer.canBuildFirst && _currentBoard.currentPlayer.tilesOwned.Count > 0)
            {
                ExecuteTrading(ref _currentBoard);
            }

            // Start construction timer
            startTime = System.DateTime.Now;
            endTime = System.DateTime.Now;
            ts = endTime.Subtract(startTime);

            //--------------------------------------------------------------
            // Construct Towers
            //--------------------------------------------------------------
            bool wasFirstTurn = _currentBoard.currentPlayer.canBuildFirst;
            if (_currentBoard.currentPlayer.canBuildFirst)
            {
                BuildFirstTurn(ref _currentBoard, startTime, endTime, ts);
            }
            else if (_currentBoard.currentPlayer.tilesOwned.Count == 0) // restart player after all tiles destroyed
            {
                BuildFirstTurn(ref _currentBoard, startTime, endTime, ts);
                System.Threading.Thread.Sleep(2000);
                BuildSubsequentTurn(ref _currentBoard, startTime, endTime, ts);
            }
            else
            {
                // Shoot first, ask questions later
                ShootTowers(ref _currentBoard, startTime, endTime, ts);

                // Restart construction timer
                startTime = System.DateTime.Now;
                endTime = System.DateTime.Now;
                ts = endTime.Subtract(startTime);
                BuildSubsequentTurn(ref _currentBoard, startTime, endTime, ts);
            }

            // Cannot shoot or trade on the first turn
            if (!wasFirstTurn)
            {
                //--------------------------------------------------------------
                // Shooting
                //--------------------------------------------------------------
                System.Threading.Thread.Sleep(1000);
                ShootTowers(ref _currentBoard, startTime, endTime, ts);

                ExecuteTrading(ref _currentBoard);
            }

            //--------------------------------------------------------------
            // Finalize
            //--------------------------------------------------------------
            //while (BoardVariables.UpdatingInfluence)
            //{
            //    System.Threading.Thread.Sleep(500);
            //}
            //BoardFunctions.UpdateInfluence(ref _currentBoard);
            // Make our minimum wait time
            endTime = DateTime.Now;
            ts = endTime - startTime;

            if (ts.TotalMilliseconds < BoardVariables.AIMinWaitTime)
                System.Threading.Thread.Sleep(BoardVariables.AIMinWaitTime - (int)ts.TotalMilliseconds);

            System.Threading.Thread.Sleep(500);

            if (!_currentBoard.gameOver)
            {
                BoardFunctions.EndTurn(ref _currentBoard, _currentBoard.networkSession);
            }
            _currentBoard.AIThinking = false;
            //System.Threading.Thread.Sleep(500);

            //_currentBoard.AIThinking = false;
        }
        static void CallbackMethod(IAsyncResult ar)
        {

            // -----------------------------------
            // OLD
            // -----------------------------------
            //Console.WriteLine("Callback fired.");

            //// Retrieve the delegate.
            //AsyncDelegate dlgt = (AsyncDelegate)ar.AsyncState;

            //// Call EndInvoke to retrieve the results.
            //string ret = dlgt.EndInvoke(out threadID, ar);

            //Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadID, ret);
        }

        private static void ExecuteTrading(ref Board _currentBoard)
        {
            if (_currentBoard.gameOver)
                return;

            // If any resource is more than 1/3 greater than another
            //      or 2/3 greater than iron and > 70,
            //      or > 90
            //      trade to acquire that resource
            //_currentBoard.TradingResource

            // If trading for iron, select the resource with the best trading ratio(s) and 
            //      trade in relation to owned iron resources
            HexTileResource tradingResource = HexTileResource.Clay;
            int tradingValue = _currentBoard.clayTrade;

            // Get best trading values
            // Wood tends to be easiest to find, so use equal/less as operator
            if (_currentBoard.stoneTrade < _currentBoard.clayTrade)// && _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] > _currentBoard.stoneTrade)
            {
                tradingResource = HexTileResource.Stone;
                tradingValue = _currentBoard.stoneTrade;
            }
            if (_currentBoard.wheatTrade < _currentBoard.clayTrade && _currentBoard.wheatTrade < _currentBoard.stoneTrade)// && _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] > _currentBoard.wheatTrade)
            {
                tradingResource = HexTileResource.Wheat;
                tradingValue = _currentBoard.wheatTrade;
            }
            if (_currentBoard.woodTrade <= _currentBoard.clayTrade && _currentBoard.woodTrade <= _currentBoard.stoneTrade && _currentBoard.woodTrade <= _currentBoard.wheatTrade)// && _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] > _currentBoard.woodTrade)
            {
                tradingResource = HexTileResource.Wood;
                tradingValue = _currentBoard.woodTrade;
            }

            // Don't actively trade for iron unless everything else is maxed out
            if (_currentBoard.TradingResource != HexTileResource.Iron)
            {
                //// If we have nothing of what they are trading...
                //if (_currentBoard.currentPlayer.CurrentResources[_currentBoard.TradingResource] == 0)
                //{
                //    // If we can never get any, trade up to at least two wheat or 5 clay/stone/wood (enough to build lvl one tower if we can)
                //    if (_currentBoard.currentPlayer.OwnedResources[_currentBoard.TradingResource] == 0)
                //    {
                //        switch (_currentBoard.TradingResource)
                //        {
                //            case HexTileResource.Wheat:
                //                // While what they are offering is less than I need, and what I have is more than the trading value...
                //                while (_currentBoard.currentPlayer.CurrentResources[_currentBoard.TradingResource] < 2 &&
                //                       _currentBoard.currentPlayer.CurrentResources[tradingResource] >= tradingValue)
                //                {
                //                    _currentBoard.currentPlayer.CurrentResources[_currentBoard.TradingResource]++;
                //                    _currentBoard.currentPlayer.CurrentResources[tradingResource] -= tradingValue;

                //                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 4 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));

                //                    switch (tradingResource)
                //                    {
                //                        case HexTileResource.Clay:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                        case HexTileResource.Stone:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 3 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                        case HexTileResource.Wood:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 5 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                    }

                //                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 " + _currentBoard.TradingResource.ToString() + ".", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));

                //                    System.Threading.Thread.Sleep(500);
                //                }
                //                break;
                //            case HexTileResource.Clay:
                //            case HexTileResource.Stone:
                //            case HexTileResource.Wood:
                //                // While what they are offering is less than I need, and what I have is more than the trading value...
                //                while (_currentBoard.currentPlayer.CurrentResources[_currentBoard.TradingResource] < 5 &&
                //                       _currentBoard.currentPlayer.CurrentResources[tradingResource] >= tradingValue)
                //                {
                //                    _currentBoard.currentPlayer.CurrentResources[_currentBoard.TradingResource]++;
                //                    _currentBoard.currentPlayer.CurrentResources[tradingResource] -= tradingValue;

                //                    // Show what they are offering
                //                    switch (_currentBoard.TradingResource)
                //                    {
                //                        case HexTileResource.Clay:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                        case HexTileResource.Stone:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 3 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                        case HexTileResource.Wood:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1" + tradingValue, new Vector2(_currentBoard.widthFraction * 5 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                    }

                //                    // Show what have given up
                //                    switch (tradingResource)
                //                    {
                //                        case HexTileResource.Clay:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                        case HexTileResource.Stone:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 3 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                        case HexTileResource.Wheat:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 4 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                        case HexTileResource.Wood:
                //                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 5 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                //                    }

                //                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 " + _currentBoard.TradingResource.ToString() + ".", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));

                //                    System.Threading.Thread.Sleep(500);
                //                }
                //                break;
                //        }
                //    }
                //}
                //// We have some of what they are trading (_currentBoard.TradingResource), but want/need more. So trade most numerous product for it.
                //else
                //{
                // if they are trading something that is not our most numerous product, trade most numerous for it (if most numerous not iron)
                // if most numerous (not iron) >= 2x least numerous (not iron), trade until least >= most
                HexTileResource mostNumerous = HexTileResource.Clay, leastNumerous = HexTileResource.Clay;
                int numberTrade = _currentBoard.clayTrade;

                // Get the least
                if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] < _currentBoard.currentPlayer.CurrentResources[leastNumerous])
                    leastNumerous = HexTileResource.Stone;
                if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] < _currentBoard.currentPlayer.CurrentResources[leastNumerous])
                    leastNumerous = HexTileResource.Wheat;
                if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] < _currentBoard.currentPlayer.CurrentResources[leastNumerous])
                    leastNumerous = HexTileResource.Wood;

                // Get the most
                if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] > _currentBoard.currentPlayer.CurrentResources[mostNumerous])
                {
                    mostNumerous = HexTileResource.Stone;
                    numberTrade = _currentBoard.stoneTrade;
                }
                if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] > _currentBoard.currentPlayer.CurrentResources[mostNumerous])
                {
                    mostNumerous = HexTileResource.Wheat;
                    numberTrade = _currentBoard.wheatTrade;
                }
                if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] >= _currentBoard.currentPlayer.CurrentResources[mostNumerous])
                {
                    mostNumerous = HexTileResource.Wood;
                    numberTrade = _currentBoard.woodTrade;
                }

                // If our least is what they are trading, trade it for our most numerous material if we have at least 2x that amount
                if (leastNumerous == _currentBoard.TradingResource &&
                    _currentBoard.currentPlayer.CurrentResources[mostNumerous] > (2 * _currentBoard.currentPlayer.CurrentResources[leastNumerous]))
                {
                    while (_currentBoard.currentPlayer.CurrentResources[mostNumerous] > _currentBoard.currentPlayer.CurrentResources[leastNumerous]
                        && _currentBoard.currentPlayer.CurrentResources[mostNumerous] >= numberTrade)
                    {
                        _currentBoard.currentPlayer.CurrentResources[leastNumerous]++;
                        _currentBoard.currentPlayer.CurrentResources[mostNumerous] -= numberTrade;

                        // Show what have given up
                        switch (mostNumerous)
                        {
                            case HexTileResource.Clay:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + numberTrade, new Vector2(_currentBoard.widthFraction + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Stone:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + numberTrade, new Vector2(_currentBoard.widthFraction * 3 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Wheat:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + numberTrade, new Vector2(_currentBoard.widthFraction * 4 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Wood:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + numberTrade, new Vector2(_currentBoard.widthFraction * 5 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                        }

                        // Show what they are offering
                        switch (_currentBoard.TradingResource)
                        {
                            case HexTileResource.Clay:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Stone:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 3 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Wheat:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 4 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Wood:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1" + tradingValue, new Vector2(_currentBoard.widthFraction * 5 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                        }

                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + numberTrade + " " + mostNumerous.ToString() + " for 1 " + leastNumerous.ToString() + ".", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));

                        System.Threading.Thread.Sleep(500);
                    }
                }
                //}
            }
            // Trade for iron only at the very end, or when 0
            else if ((_currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] > 90 &&
                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] > 90 &&
                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] > 90 &&
                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] > 90 &&
                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] < 99) ||
                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] == 0)
            {
                if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] == 0)
                {
                    // Trade for just one
                    if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] > _currentBoard.woodTrade)
                    {
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron]++;
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] -= _currentBoard.woodTrade;
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 2 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + _currentBoard.woodTrade, new Vector2(_currentBoard.widthFraction * 5 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + _currentBoard.woodTrade + " Wood for 1 Iron.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));
                    }
                    else if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] > _currentBoard.clayTrade)
                    {
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron]++;
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] -= _currentBoard.clayTrade;
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 2 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + _currentBoard.clayTrade, new Vector2(_currentBoard.widthFraction + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + _currentBoard.clayTrade + " Clay for 1 Iron.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));
                    }
                    else if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] > _currentBoard.wheatTrade)
                    {
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron]++;
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] -= _currentBoard.wheatTrade;
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 2 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + _currentBoard.wheatTrade, new Vector2(_currentBoard.widthFraction * 4 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + _currentBoard.wheatTrade + " Wheat for 1 Iron.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));
                    }
                    else if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] > _currentBoard.stoneTrade)
                    {
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron]++;
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] -= _currentBoard.stoneTrade;
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 2 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + _currentBoard.stoneTrade, new Vector2(_currentBoard.widthFraction * 3 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + _currentBoard.stoneTrade + " Stone for 1 Iron.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));
                    }

                    System.Threading.Thread.Sleep(500);
                }
                else
                {
                    // Trade within ranges
                    while (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] < 99 &&
                        _currentBoard.currentPlayer.CurrentResources[tradingResource] > 60)
                    {
                        _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron]++;
                        _currentBoard.currentPlayer.CurrentResources[tradingResource] -= tradingValue;

                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("+1", new Vector2(_currentBoard.widthFraction * 2 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));

                        switch (tradingResource)
                        {
                            case HexTileResource.Clay:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Stone:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 3 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Wheat:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 4 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                            case HexTileResource.Wood:
                                _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-" + tradingValue, new Vector2(_currentBoard.widthFraction * 5 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color)); break;
                        }

                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " traded " + tradingValue + " " + tradingResource.ToString() + " for 1 Iron.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));

                        System.Threading.Thread.Sleep(500);
                    }
                }
            }

            System.Threading.Thread.Sleep(1000);
        }

        private static void BuildFirstTurn(ref Board _currentBoard, DateTime startTime, DateTime endTime, TimeSpan ts)
        {
            // We will always enter this with at least enough for a base influence tower
            // Can only build once on the first turn
            // find balanced cluster, distance calculation between non-iron resources + distance from iron resource
            //      Do this by searching 3 levels out and calculating a resource value, then selecting the highest.
            //      Separation by water reduces value by a certain percentage.
            int indexBestTile = -1, bestTileScore = -1;
            int currentScore = 0;
            int clayScore = 0, ironScore = 0, stoneScore = 0, woodScore = 0, wheatScore = 0;

            for (int i = 0; i < _currentBoard.Tiles.Length; i++)
            {
                // check if we're taking too long, every 20 tiles (reduces overhead)
                if (i % 20 == 0)
                {
                    endTime = System.DateTime.Now;
                    ts = endTime.Subtract(startTime);
                    if (ts.TotalMilliseconds > BoardVariables.AIMaxWaitTime)
                        break;
                }

                // Skip any tiles we cannot use
                if (_currentBoard.Tiles[i].TileBase == HexTileBase.Sand ||
                    _currentBoard.Tiles[i].TileBase == HexTileBase.Water ||
                    _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Wheat ||
                    _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Mountain1 ||
                    _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Mountain2 ||
                    _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Mountain3 ||
                   (_currentBoard.Tiles[i].tileOwner != _currentBoard.currentPlayer.side && _currentBoard.Tiles[i].tileOwner != PlayerColor.None) ||
                    _currentBoard.Tiles[i].ManMadeModifier == HexTileManMadeModifier.InfluenceTower3 ||
                    _currentBoard.Tiles[i].ManMadeModifier == HexTileManMadeModifier.DefensiveTower)
                {
                    continue;
                }

                // Search three levels out, multiplying closest by 3, next by 2, last just 1
                //      leaving iron as slightly less valuable, since it is not for "building"
                switch (_currentBoard.Tiles[i].ResourceModifier)
                {
                    case HexTileResource.Clay:
                        clayScore += 3; break;
                    case HexTileResource.Iron:
                        ironScore += 3; break;
                    case HexTileResource.Stone:
                        stoneScore += 3; break;
                    case HexTileResource.Wheat:
                        wheatScore += 3; break;
                    case HexTileResource.Wood:
                        woodScore += 3; break;
                }

                for (int j = 0; j < 6; j++)
                {
                    if (_currentBoard.Tiles[i].Neighbors[j] == null)
                        continue;

                    switch (_currentBoard.Tiles[i].Neighbors[j].ResourceModifier)
                    {
                        case HexTileResource.Clay:
                            clayScore += 3; break;
                        case HexTileResource.Iron:
                            ironScore += 3; break;
                        case HexTileResource.Stone:
                            stoneScore += 3; break;
                        case HexTileResource.Wheat:
                            wheatScore += 3; break;
                        case HexTileResource.Wood:
                            woodScore += 3; break;
                    }

                    // Don't look so far for defensive
                    if (_currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                        _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                        _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2)
                        continue;

                    for (int k = 0; k < 6; k++)
                    {
                        if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k] == null)
                            continue;

                        switch (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].ResourceModifier)
                        {
                            case HexTileResource.Clay:
                                clayScore += 2; break;
                            case HexTileResource.Iron:
                                ironScore += 2; break;
                            case HexTileResource.Stone:
                                stoneScore += 2; break;
                            case HexTileResource.Wheat:
                                wheatScore += 2; break;
                            case HexTileResource.Wood:
                                woodScore += 2; break;
                        }

                        for (int l = 0; l < 6; l++)
                        {
                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].Neighbors[l] == null)
                                continue;

                            switch (_currentBoard.Tiles[i].Neighbors[j].ResourceModifier)
                            {
                                case HexTileResource.Clay:
                                    clayScore++; break;
                                case HexTileResource.Iron:
                                    ironScore++; break;
                                case HexTileResource.Stone:
                                    stoneScore++; break;
                                case HexTileResource.Wheat:
                                    wheatScore++; break;
                                case HexTileResource.Wood:
                                    woodScore++; break;
                            }
                        }
                    }
                }

                // Cast the score, adjusting for certain variables
                currentScore = clayScore + (int)(ironScore * 0.5f) + stoneScore + woodScore + wheatScore;

                // value places with more varied resources
                currentScore += (((clayScore > 0 ? 1 : 0) + (ironScore > 0 ? 1 : 0) + (stoneScore > 0 ? 1 : 0) + (wheatScore > 0 ? 1 : 0) + (woodScore > 0 ? 1 : 0)) * 3);

                // don't build a defensive tower when restarting, easier than an actual check of resources/refinding best tile
                if ((_currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                    _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                    _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2) &&
                    !_currentBoard.currentPlayer.canBuildFirst)
                {
                    currentScore = -1;
                }

                // Compare the scores
                if (currentScore > bestTileScore)
                {
                    bestTileScore = currentScore;
                    indexBestTile = i;
                }

                // reset score
                clayScore = ironScore = stoneScore = woodScore = wheatScore = 0;
            }

            // build when possible
            if (indexBestTile > -1)
            {
                BoardFunctions.UpgradeTower(ref _currentBoard, indexBestTile, _currentBoard.currentPlayer.side, _currentBoard.networkSession);

                switch (_currentBoard.Tiles[indexBestTile].ManMadeModifier)
                {
                    case HexTileManMadeModifier.DefensiveTower:
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " built a new defensive tower.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " built a new defensive tower.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));
                        break;
                    case HexTileManMadeModifier.InfluenceTower1:
                        _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " built a new influence tower.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " built a new influence tower.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));
                        break;
                }

                BoardFunctions.UpdateInfluence(ref _currentBoard);
                //_currentBoard.currentPlayer.UpdateTower(indexBestTile, _currentBoard.currentPlayer.side);

                // Move ai camera to latest move and wait a transition time
                _currentBoard.currentPlayer.Camera.DesiredTarget = _currentBoard.Tiles[indexBestTile].Position;
                _currentBoard.currentPlayer.Camera.DesiredPosition = new Vector3(_currentBoard.Tiles[indexBestTile].Position.X, _currentBoard.Tiles[indexBestTile].Position.Y + 400, _currentBoard.Tiles[indexBestTile].Position.Z - 200);
            }
        }

        private static void BuildSubsequentTurn(ref Board _currentBoard, DateTime startTime, DateTime endTime, TimeSpan ts)
        {
            // find balanced cluster, distance calculation between non-iron resources + distance from iron resource
            //      Do this by searching 3 levels out and calculating a resource value, then selecting the highest.
            //      Separation by water reduces value by a certain percentage.
            bool buildBridge = false;
            int bridgeIndex = -1;
            int indexBestTile = -1;
            float bestTileScore = -1;
            float currentScore = 0;
            float clayScore = 0, ironScore = 0, stoneScore = 0, woodScore = 0, wheatScore = 0;
            int counter = 20;
            bool canContinueBuild = true;

            // Build as much as we can
            while (!_currentBoard.gameOver && canContinueBuild && ts.TotalMilliseconds < BoardVariables.AIMaxWaitTime)
            {
                buildBridge = false;
                bridgeIndex = indexBestTile = -1;
                bestTileScore = -1;
                clayScore = ironScore = stoneScore = woodScore = wheatScore = 0;
                counter = 20;

                // The list for all reachable tiles that we can build on
                List<int> tilesReachable = new List<int>(_currentBoard.currentPlayer.tilesOwned.Count * 2);
                for (int i = 0; i < _currentBoard.currentPlayer.tilesOwned.Count; i++)
                {
                    // Get the immediate tile
                    tilesReachable.Add(_currentBoard.currentPlayer.tilesOwned[i]);

                    // Get neighbor tiles
                    for (int j = 0; j < 6; j++)
                    {
                        if (_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j] == null ||
                            _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].TileBase == HexTileBase.Sand ||
                            _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].TileBase == HexTileBase.Water)
                            continue;

                        if (!tilesReachable.Contains(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].IndexInBoard))
                        {
                            tilesReachable.Add(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].IndexInBoard);
                        }

                        for (int k = 0; k < 6; k++)
                        {
                            if (_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].Neighbors[k] == null ||
                                _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].Neighbors[k].TileBase == HexTileBase.Sand ||
                                _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].Neighbors[k].TileBase == HexTileBase.Water)
                                continue;

                            if (!tilesReachable.Contains(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].Neighbors[k].IndexInBoard))
                            {
                                tilesReachable.Add(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Neighbors[j].Neighbors[k].IndexInBoard);
                            }
                        }
                    }
                }

                foreach (int i in tilesReachable)
                {
                    // check if we're taking too long, every 20 tiles (reduces overhead)
                    // Checks at 0 and every multiple after that
                    if (counter == 20)
                    {
                        counter = 0;
                        endTime = System.DateTime.Now;
                        ts = endTime.Subtract(startTime);
                        if (ts.TotalMilliseconds > BoardVariables.AIMaxWaitTime)
                            break;
                    }
                    else
                        counter++;

                    // Skip any tiles we cannot use
                    if ((_currentBoard.Tiles[i].tileOwner != _currentBoard.currentPlayer.side && _currentBoard.Tiles[i].tileOwner != PlayerColor.None) ||
                        //_currentBoard.Tiles[i].TileBase == HexTileBase.Sand ||
                        //_currentBoard.Tiles[i].TileBase == HexTileBase.Water ||
                        _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Wheat ||
                        _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Mountain1 ||
                        _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Mountain2 ||
                        _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Mountain3 ||
                        _currentBoard.Tiles[i].ManMadeModifier == HexTileManMadeModifier.InfluenceTower3 ||
                        _currentBoard.Tiles[i].ManMadeModifier == HexTileManMadeModifier.DefensiveTower ||
                        //_currentBoard.Tiles[i].value == 3)
                        (_currentBoard.Tiles[i].value == 3 && _currentBoard.Tiles[i].ManMadeModifier == HexTileManMadeModifier.None)) // Don't build on maxed out empty tiles
                    {
                        continue;
                    }

                    // Check within a two tile limit for continuous influence
                    bool canBuild = false;
                    if (_currentBoard.Tiles[i].tileOwner == _currentBoard.currentPlayer.side)
                        canBuild = true;

                    if (!canBuild)
                    {
                        for (int j = 0; j < 6; j++)
                        {
                            if (_currentBoard.Tiles[i].Neighbors[j] == null)
                                continue;

                            if (_currentBoard.Tiles[i].Neighbors[j].tileOwner == _currentBoard.currentPlayer.side)
                            {
                                canBuild = true;
                                j = 6;
                            }
                            else
                            {
                                for (int k = 0; k < 6; k++)
                                {
                                    if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k] == null)
                                        continue;

                                    if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side)
                                    {
                                        canBuild = true;
                                        j = k = 6;
                                    }
                                }
                            }
                        }
                    }

                    // Goto next tile if can't build at this point
                    if (!canBuild)
                        continue;

                    // Search three levels out, multiplying closest by 3, next by 2, last just 1
                    //      leaving iron as slightly less valuable, since it is not for "building"
                    switch (_currentBoard.Tiles[i].ResourceModifier)
                    {
                        case HexTileResource.Clay:
                            clayScore += 3; break;
                        case HexTileResource.Iron:
                            ironScore += 3; break;
                        case HexTileResource.Stone:
                            stoneScore += 3; break;
                        case HexTileResource.Wheat:
                            wheatScore += 3; break;
                        case HexTileResource.Wood:
                            woodScore += 3; break;
                    }

                    for (int j = 0; j < 6; j++)
                    {
                        if (_currentBoard.Tiles[i].Neighbors[j] == null)
                            continue;

                        switch (_currentBoard.Tiles[i].Neighbors[j].ResourceModifier)
                        {
                            case HexTileResource.Clay:
                                clayScore += 3; break;
                            case HexTileResource.Iron:
                                ironScore += 3; break;
                            case HexTileResource.Stone:
                                stoneScore += 3; break;
                            case HexTileResource.Wheat:
                                wheatScore += 3; break;
                            case HexTileResource.Wood:
                                woodScore += 3; break;
                        }

                        // Don't look so far for defensive
                        if (_currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                            _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                            _currentBoard.Tiles[i].NaturalModifier == HexTileNaturalModifier.Hill2)
                            continue;

                        // Reduce distant tiles if they are owned by opposing sides
                        for (int k = 0; k < 6; k++)
                        {
                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k] == null)
                                continue;

                            switch (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].ResourceModifier)
                            {
                                case HexTileResource.Clay:
                                    clayScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 2 : 1); break;
                                case HexTileResource.Iron:
                                    ironScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 2 : 1); break;
                                case HexTileResource.Stone:
                                    stoneScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 2 : 1); break;
                                case HexTileResource.Wheat:
                                    wheatScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 2 : 1); break;
                                case HexTileResource.Wood:
                                    woodScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 2 : 1); break;
                            }

                            for (int l = 0; l < 6; l++)
                            {
                                if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].Neighbors[l] == null)
                                    continue;

                                switch (_currentBoard.Tiles[i].Neighbors[j].ResourceModifier)
                                {
                                    case HexTileResource.Clay:
                                        clayScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 1 : 0.5f); break;
                                    case HexTileResource.Iron:
                                        ironScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 1 : 0.5f); break;
                                    case HexTileResource.Stone:
                                        stoneScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 1 : 0.5f); break;
                                    case HexTileResource.Wheat:
                                        wheatScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 1 : 0.5f); break;
                                    case HexTileResource.Wood:
                                        woodScore += ((_currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner == _currentBoard.currentPlayer.side &&
                                                    _currentBoard.Tiles[i].Neighbors[j].Neighbors[k].tileOwner != PlayerColor.None) ? 1 : 0.5f); break;
                                }
                            }
                        }
                    }

                    // Adjust score according to resources already owned (i.e. if owned much more wood, wood is less valuable to get)
                    // Store the total resources owned inside "None", as it already exists and we don't need to track the total
                    // If any resource out of five is more than roughly 1/3 the total, reduce appropriately (less for iron)
                    if (_currentBoard.currentPlayer.OwnedResources[HexTileResource.None] > 0)
                    {
                        clayScore -= (_currentBoard.currentPlayer.OwnedResources[HexTileResource.Clay] / (float)_currentBoard.currentPlayer.OwnedResources[HexTileResource.None] > 0.30f ? (clayScore / 2) : 0);
                        ironScore -= (_currentBoard.currentPlayer.OwnedResources[HexTileResource.Iron] / (float)_currentBoard.currentPlayer.OwnedResources[HexTileResource.None] > 0.20f ? (ironScore / 2) : 0);
                        stoneScore -= (_currentBoard.currentPlayer.OwnedResources[HexTileResource.Stone] / (float)_currentBoard.currentPlayer.OwnedResources[HexTileResource.None] > 0.30f ? (stoneScore / 2) : 0);
                        wheatScore -= (_currentBoard.currentPlayer.OwnedResources[HexTileResource.Wheat] / (float)_currentBoard.currentPlayer.OwnedResources[HexTileResource.None] > 0.30f ? (wheatScore / 2) : 0);
                        woodScore -= (_currentBoard.currentPlayer.OwnedResources[HexTileResource.Wood] / (float)_currentBoard.currentPlayer.OwnedResources[HexTileResource.None] > 0.30f ? (woodScore / 2) : 0);
                    }

                    // Cast the score, adjusting for certain variables
                    currentScore = clayScore + (ironScore * 0.5f) + stoneScore + woodScore + wheatScore;

                    // value places with more varied resources
                    currentScore += (((clayScore > 0 ? 1 : 0) + (ironScore > 0 ? 1 : 0) + (stoneScore > 0 ? 1 : 0) + (wheatScore > 0 ? 1 : 0) + (woodScore > 0 ? 1 : 0)) * 6);

                    // Reduce score when neighboring friendly towers
                    for (int j = 0; j < 6; j++)
                    {
                        if (_currentBoard.Tiles[i].Neighbors[j] == null)
                        {
                            currentScore--;
                            continue;
                        }

                        // Don't build influence towers near opposing defensive towers
                        if (_currentBoard.Tiles[i].NaturalModifier != HexTileNaturalModifier.Hill2 &&
                            _currentBoard.Tiles[i].NaturalModifier != HexTileNaturalModifier.Hill2 &&
                            _currentBoard.Tiles[i].NaturalModifier != HexTileNaturalModifier.Hill2)
                        {
                            if (_currentBoard.Tiles[i].Neighbors[j].ManMadeModifier == HexTileManMadeModifier.DefensiveTower &&
                                _currentBoard.Tiles[i].Neighbors[j].tileOwner != _currentBoard.currentPlayer.side)
                            {
                                currentScore = -1;
                            }
                        }

                        // Don't build near friendly towers
                        if (_currentBoard.Tiles[i].Neighbors[j].ManMadeModifier != HexTileManMadeModifier.None &&
                            _currentBoard.Tiles[i].Neighbors[j].ManMadeModifier != HexTileManMadeModifier.Bridge &&
                            _currentBoard.Tiles[i].Neighbors[j].tileOwner == _currentBoard.currentPlayer.side)
                        {
                            currentScore /= 5;
                        }

                        // Sand is less desirable up close
                        if (_currentBoard.Tiles[i].Neighbors[j].TileBase == HexTileBase.Sand)
                        {
                            currentScore--;
                        }

                        // Check water. If found, check around the water and only build bridges if not next to other bridges
                        if (_currentBoard.Tiles[i].Neighbors[j].TileBase == HexTileBase.Water &&
                            _currentBoard.Tiles[i].Neighbors[j].ManMadeModifier != HexTileManMadeModifier.Bridge &&
                            _currentBoard.Tiles[i].tileOwner == _currentBoard.currentPlayer.side &&
                            _currentBoard.Tiles[i].value > 1)
                        {
                            buildBridge = true;
                            bridgeIndex = _currentBoard.Tiles[i].Neighbors[j].IndexInBoard;

                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[0] != null &&
                                _currentBoard.Tiles[i].Neighbors[j].Neighbors[0].ManMadeModifier == HexTileManMadeModifier.Bridge)
                                buildBridge = false;
                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[1] != null &&
                                _currentBoard.Tiles[i].Neighbors[j].Neighbors[1].ManMadeModifier == HexTileManMadeModifier.Bridge)
                                buildBridge = false;
                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[2] != null &&
                                _currentBoard.Tiles[i].Neighbors[j].Neighbors[2].ManMadeModifier == HexTileManMadeModifier.Bridge)
                                buildBridge = false;
                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[3] != null &&
                                _currentBoard.Tiles[i].Neighbors[j].Neighbors[3].ManMadeModifier == HexTileManMadeModifier.Bridge)
                                buildBridge = false;
                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[4] != null &&
                                _currentBoard.Tiles[i].Neighbors[j].Neighbors[4].ManMadeModifier == HexTileManMadeModifier.Bridge)
                                buildBridge = false;
                            if (_currentBoard.Tiles[i].Neighbors[j].Neighbors[5] != null &&
                                _currentBoard.Tiles[i].Neighbors[j].Neighbors[5].ManMadeModifier == HexTileManMadeModifier.Bridge)
                                buildBridge = false;
                        }
                    }

                    // Lower the value the higher the score
                    //if (_currentBoard.Tiles[i].value > 0)
                    //    currentScore *= (1 / _currentBoard.Tiles[i].value);
                    //else
                    //{
                    //    currentScore += (currentScore * 1.5f);
                    //}

                    // Compare the scores
                    if (currentScore >= bestTileScore)
                    {
                        bestTileScore = currentScore;
                        indexBestTile = i;
                    }

                    // reset score
                    clayScore = ironScore = stoneScore = woodScore = wheatScore = 0;
                }   // End for loop

                // build when possible
                if (indexBestTile > -1)
                {
                    // Check whether we have resources to build
                    bool resourcesAvailable = false;
                    if (_currentBoard.Tiles[indexBestTile].ManMadeModifier == HexTileManMadeModifier.None)
                    {
                        if (_currentBoard.Tiles[indexBestTile].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                            _currentBoard.Tiles[indexBestTile].NaturalModifier == HexTileNaturalModifier.Hill2 ||
                            _currentBoard.Tiles[indexBestTile].NaturalModifier == HexTileNaturalModifier.Hill2)
                        {
                            if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] >= BoardVariables.DefensiveClayCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] >= BoardVariables.DefensiveWoodCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] >= BoardVariables.DefensiveStoneCost)
                            {
                                resourcesAvailable = true;
                            }
                        }
                        else
                        {
                            if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] >= BoardVariables.Influence1ClayCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] >= BoardVariables.Influence1WoodCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] >= BoardVariables.Influence1StoneCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] >= BoardVariables.Influence1WheatCost)
                            {
                                resourcesAvailable = true;
                            }
                        }
                    }
                    else
                    {
                        if (_currentBoard.Tiles[indexBestTile].ManMadeModifier == HexTileManMadeModifier.InfluenceTower1)
                        {
                            if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] >= BoardVariables.Influence2ClayCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] >= BoardVariables.Influence2WoodCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] >= BoardVariables.Influence2StoneCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] >= BoardVariables.Influence2WheatCost)
                            {
                                resourcesAvailable = true;
                            }
                        }
                        else
                        {
                            if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] >= BoardVariables.Influence3ClayCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] >= BoardVariables.Influence3WoodCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] >= BoardVariables.Influence3StoneCost &&
                                _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wheat] >= BoardVariables.Influence3WheatCost)
                            {
                                resourcesAvailable = true;
                            }
                        }
                    }

                    if (resourcesAvailable)
                    {
                        canContinueBuild = BoardFunctions.UpgradeTower(ref _currentBoard, indexBestTile, _currentBoard.currentPlayer.side, _currentBoard.networkSession);

                        if (canContinueBuild)
                        {
                            BoardFunctions.UpdateInfluence(ref _currentBoard);

                            switch (_currentBoard.Tiles[indexBestTile].ManMadeModifier)
                            {
                                case HexTileManMadeModifier.DefensiveTower:
                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " built a new defensive tower.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " built a new defensive tower.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black)); break;
                                case HexTileManMadeModifier.InfluenceTower1:
                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " built a new influence tower.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " built a new influence tower.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black)); break;
                                case HexTileManMadeModifier.InfluenceTower2:
                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " upgraded to a level 2 influence tower.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " upgraded to a level 2 influence tower.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black)); break;
                                case HexTileManMadeModifier.InfluenceTower3:
                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " upgraded to a level 3 influence tower.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " upgraded to a level 3 influence tower.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black)); break;
                            }
                        }

                        // build a bridge if we can
                        if (buildBridge &&
                            _currentBoard.currentPlayer.CurrentResources[HexTileResource.Wood] >= BoardVariables.BridgeWoodCost &&
                            _currentBoard.currentPlayer.CurrentResources[HexTileResource.Stone] >= BoardVariables.BridgeStoneCost &&
                            _currentBoard.currentPlayer.CurrentResources[HexTileResource.Clay] >= BoardVariables.BridgeClayCost)
                        {
                            System.Threading.Thread.Sleep(500);

                            BoardFunctions.UpgradeTower(ref _currentBoard, bridgeIndex, _currentBoard.currentPlayer.side, _currentBoard.networkSession);
                            BoardFunctions.UpdateInfluence(ref _currentBoard);
                            _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " built a bridge.", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " built a bridge.").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black)); break;
                        }

                        // Move ai camera to latest move and wait a transition time
                        _currentBoard.currentPlayer.Camera.DesiredTarget = _currentBoard.Tiles[indexBestTile].Position;
                        _currentBoard.currentPlayer.Camera.DesiredPosition = new Vector3(_currentBoard.Tiles[indexBestTile].Position.X, _currentBoard.Tiles[indexBestTile].Position.Y + 400, _currentBoard.Tiles[indexBestTile].Position.Z - 200);
                    }   // End if resources available check
                    else
                    {
                        canContinueBuild = false;
                    }
                }
                else
                {
                    canContinueBuild = false;
                }

                // take break to allow player to see AI move
                if (canContinueBuild)
                {
                    while (BoardVariables.UpdatingInfluence)
                    {
                        System.Threading.Thread.Sleep(500);
                    }

                    System.Threading.Thread.Sleep(2000);
                }

                ts = endTime.Subtract(startTime);
            }       // End while loop
        }

        private static void ShootTowers(ref Board _currentBoard, DateTime startTime, DateTime endTime, TimeSpan ts)
        {
            bool canShoot = (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] > 0);
            // Restart our time, check by half
            startTime = DateTime.Now;
            endTime = DateTime.Now;
            ts = endTime - startTime;

            while (!_currentBoard.gameOver && canShoot && ts.TotalMilliseconds < (BoardVariables.AIMaxWaitTime / 2))
            {
                // Start false, therefore, if no shots are found, we exit the loop
                canShoot = false;

                for (int i = 0; i < _currentBoard.currentPlayer.tilesOwned.Count; i++)
                {
                    // check if we're taking too long, every 20 tiles (reduces overhead)
                    // Checks at 0 and every multiple after that
                    if (i == 20)
                    {
                        endTime = System.DateTime.Now;
                        ts = endTime.Subtract(startTime);
                        if (ts.TotalMilliseconds > (BoardVariables.AIMaxWaitTime / 2))
                            break;
                    }

                    // Check if we can fire
                    if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] > 0 &&
                        _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].ManMadeModifier != HexTileManMadeModifier.None &&
                        _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].ManMadeModifier != HexTileManMadeModifier.Bridge)
                    {
                        // Check each opposing player
                        foreach (KeyValuePair<PlayerColor, Player> p in _currentBoard.Players)
                        {
                            if (p.Value.Side != _currentBoard.currentPlayer.Side)
                            {
                                for (int j = 0; j < p.Value.tilesOwned.Count; j++)
                                {
                                    if (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] > 0 &&
                                        _currentBoard.Tiles[p.Value.tilesOwned[j]].ManMadeModifier != HexTileManMadeModifier.None &&
                                        _currentBoard.Tiles[p.Value.tilesOwned[j]].ManMadeModifier != HexTileManMadeModifier.DefensiveTower &&
                                        _currentBoard.Tiles[p.Value.tilesOwned[j]].ManMadeModifier != HexTileManMadeModifier.Bridge)
                                    {
                                        switch (_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].ManMadeModifier)
                                        {
                                            case HexTileManMadeModifier.DefensiveTower:
                                                if (Vector3.Distance(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position, _currentBoard.Tiles[p.Value.tilesOwned[j]].Position) < BoardVariables.cannonDistance)
                                                {
                                                    _currentBoard.currentPlayer.SelectedTile = _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]];

                                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " attacked and reduced " + _currentBoard.Tiles[p.Value.tilesOwned[j]].tileOwner.ToString() + ".", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " attacked and reduced " + _currentBoard.Tiles[p.Value.tilesOwned[j]].tileOwner.ToString() + ".").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));

                                                    BoardFunctions.ReduceTower(ref _currentBoard, _currentBoard.currentPlayer.SelectedTile.IndexInBoard, _currentBoard.Tiles[p.Value.tilesOwned[j]].IndexInBoard, _currentBoard.networkSession);
                                                    BoardFunctions.UpdateInfluence(ref _currentBoard);

                                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-1", new Vector2(_currentBoard.widthFraction * 2 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                                                    _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron]--;

                                                    // if we've shot, make sure we have enough iron to continue, or exit early if we can
                                                    canShoot = (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] > 0);

                                                    // Move ai camera to latest move and wait a transition time
                                                    _currentBoard.currentPlayer.Camera.DesiredTarget = _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position;
                                                    _currentBoard.currentPlayer.Camera.DesiredPosition = new Vector3(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position.X, _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position.Y + 400, _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position.Z - 200);

                                                    System.Threading.Thread.Sleep(1000);

                                                    j = p.Value.tilesOwned.Count - 1;
                                                    i = _currentBoard.currentPlayer.tilesOwned.Count - 1;
                                                }
                                                break;
                                            case HexTileManMadeModifier.InfluenceTower1:
                                            case HexTileManMadeModifier.InfluenceTower2:
                                            case HexTileManMadeModifier.InfluenceTower3:
                                                if (Vector3.Distance(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position, _currentBoard.Tiles[p.Value.tilesOwned[j]].Position) < ((int)_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].ManMadeModifier * BoardVariables.cannonDistance))
                                                {
                                                    _currentBoard.currentPlayer.SelectedTile = _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]];

                                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine(_currentBoard.currentPlayer.Side.ToString() + " attacked and reduced " + _currentBoard.Tiles[p.Value.tilesOwned[j]].tileOwner.ToString() + ".", new Vector2((_currentBoard.screenWidth / 2) - (_currentBoard.spriteFontSmall.MeasureString(_currentBoard.currentPlayer.Side.ToString() + " attacked and reduced " + _currentBoard.Tiles[p.Value.tilesOwned[j]].tileOwner.ToString() + ".").X / 2), _currentBoard.heightPadding * 6), _currentBoard.spriteFontSmall, Color.White, 0, 2000, -Vector2.UnitY, 0.05f, 1.0f, -0.0015f, 1000, 0.0f, 2000, DynamicTextLine.OriginType.TopLeft, Color.Black));

                                                    BoardFunctions.ReduceTower(ref _currentBoard, _currentBoard.currentPlayer.SelectedTile.IndexInBoard, _currentBoard.Tiles[p.Value.tilesOwned[j]].IndexInBoard, _currentBoard.networkSession);
                                                    BoardFunctions.UpdateInfluence(ref _currentBoard);

                                                    _currentBoard.dynamicText.DynamicTextLines.Add(new DynamicTextLine("-1", new Vector2(_currentBoard.widthFraction * 2 + 100, _currentBoard.heightPadding * 9 - 64), _currentBoard.spriteFont, Color.White, 0, 1000, -Vector2.UnitY, 0.1f, 1.0f, -0.003f, 500, 0.0f, 1000, DynamicTextLine.OriginType.TopLeft, _currentBoard.currentPlayer.color));
                                                    _currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron]--;

                                                    // if we've shot, make sure we have enough iron to continue, or exit early if we can
                                                    canShoot = (_currentBoard.currentPlayer.CurrentResources[HexTileResource.Iron] > 0);

                                                    // Move ai camera to latest move and wait a transition time
                                                    _currentBoard.currentPlayer.Camera.DesiredTarget = _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position;
                                                    _currentBoard.currentPlayer.Camera.DesiredPosition = new Vector3(_currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position.X, _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position.Y + 400, _currentBoard.Tiles[_currentBoard.currentPlayer.tilesOwned[i]].Position.Z - 200);

                                                    System.Threading.Thread.Sleep(1000);

                                                    j = p.Value.tilesOwned.Count - 1;
                                                    i = _currentBoard.currentPlayer.tilesOwned.Count - 1;
                                                }
                                                break;
                                        }
                                    }
                                }
                            }
                        }       // Exit player loop
                    }           // Exit current player tower IF
                }               // Exit current player owned tiles loop
            }                   // Exit can shoot and time loop
        }

        static private void UpdateInfluenceThreaded(Board _currentBoard)
        {
            BoardFunctions.UpdateInfluence(ref _currentBoard);
        }

        static private void EndTurnThreaded(Board _currentBoard)
        {
            BoardFunctions.EndTurn(ref _currentBoard, _currentBoard.networkSession);
        }
    }
}
